package com.lowkey.dao;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.lowkey.bean.Book;
import com.lowkey.bean.Style;
import com.lowkey.cache.CacheFactory;
import com.lowkey.cache.CacheMap;
import com.lowkey.dataSource.DBControl;
import com.lowkey.sqlTools.LowkeyDetachedCriteria;
import com.lowkey.sqlTools.Restrictions;
import com.lowkey.sqlTools.SQLInfo;
import com.lowkey.sqlTools.SQLTools;
import com.lowkey.tableInfo.Id;
import com.lowkey.tableInfo.ManyToOne;
import com.lowkey.tableInfo.OneToMany;
import com.lowkey.tableInfo.Property;
import com.lowkey.tableInfo.TableInfo;
import com.lowkey.tools.Constant;

public class lowkeyDaoImpl implements lowkeyDao {

	private DBControl db;
 
	public void save(Object o) {
		db = new DBControl();
		Class c = o.getClass();
		String className = c.getName();
		TableInfo table = Constant.TABLEMAP.get(className);
		Id id = table.getId();
		List<Property> plist = table.getPropertys();
		List<ManyToOne> manyList = table.getManyList();
		String idName = id.getName();
		String idColumn = id.getColumn();
		Boolean idUpBySelf = id.getUpByself();
		Object idValue = getValueByObject(idName, o);
		StringBuffer sb = new StringBuffer("insert into ").append(
				table.getTableName()).append(" (");
//		if(!idUpBySelf){//采用非自增长 主键策略
//			sb.append(idColumn).append(",");
//		}
		sb.append(idColumn).append(",");
		List<Object> valueList = new ArrayList<Object>();
		if (plist != null) {
			for (Property p : plist) {
				String pName = p.getName();
				String pColumn = p.getColumn();
				sb.append(pColumn).append(",");
				valueList.add(getValueByObject(pName, o));
			} 
		}
		if (manyList != null) {// 说明有外键,需要添加
			for (ManyToOne many : manyList) {
				String manyname = many.getManyName();
				String manyColumn = many.getManyColumn();
				Object manyObject = getValueByObject(manyname, o);
				Object manyValue = getValueByObject(manyColumn, manyObject);
				sb.append(manyColumn).append(",");
				valueList.add(manyValue);
			}
		}
		// 获得实体对象中具体的值
		String sqlString = sb.substring(0, sb.toString().length() - 1);
		 
		sqlString += ") values(" ;
		//id问题:
		//if(!idUpBySelf){
			if(idValue instanceof String){
				sqlString+="'"+idValue+"',";
			}else{
				sqlString += idValue+",";
			}
		//} 
		
		for (Object value : valueList) {
			if(value instanceof String){
				sqlString += "'" + value + "',";
			}else{
				sqlString += value + ",";
			}
		}
		sqlString = sqlString.substring(0, sqlString.length() - 1) + ")";
		System.out.println(sqlString);
		db.setData(sqlString);
		db.close();
	}

	private Object getValueByObject(String name, Object o) {
		Field f = null;// 通过反射获得 类的字段名称！
		Object value = null;//
		try {
			f = o.getClass().getDeclaredField(name);
			f.setAccessible(true);
			value = f.get(o);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return value;
	}

	// 更新的时候要考虑manyToOne
	// UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
	public void update(Object o) {
		db = new DBControl();
		Class c = o.getClass();
		String className = c.getName();
		TableInfo table = Constant.TABLEMAP.get(className);
		Id id = table.getId();
		String idName = id.getName();
		String idColumn = id.getColumn();
		// 用作拼接sql语句的条件
		Object idValue = getValueByObject(idName, o);

		List<String> columnList = new ArrayList<String>();// 拼接会用到
		List<Object> valueList = new ArrayList<Object>();// 拼接会用到

		List<Property> plist = table.getPropertys();// 扫描送进来的实体和对象,根据配置文件 两个list
		for (Property p : plist) {
			String pName = p.getName();
			Object pValue = getValueByObject(pName, o);
			if (pValue != null) {
				valueList.add(pValue);
				columnList.add(p.getColumn());
			}
		}
		List<ManyToOne> mlist = table.getManyList();// 扫描...(如上)
		if (mlist != null) {
			for (ManyToOne m : mlist) {
				String manyName = m.getManyName();
				Object manyValue = getValueByObject(manyName, o);// 这里可以获得manyToOne
																	// 中 one的对象.
				if (manyValue != null) {
					String mValue_Column = m.getManyColumn();// one 的列名
					Object mValue_Value = getValueByObject(mValue_Column,
							manyValue);// 这里就获得one 的一个值了.
					columnList.add(mValue_Column);
					valueList.add(mValue_Value);
				}
			}
		}
		StringBuffer sb = new StringBuffer("update ");
		sb.append(table.getTableName()).append(" set ");
		for (int i = 0; i < valueList.size(); i++) {
			String column = columnList.get(i);
			Object value = valueList.get(i);
			if(value instanceof String){
				sb.append(column).append("='").append(value).append("'");
			}else{
				sb.append(column).append("=").append(value);
			}
			if (i + 1 != valueList.size()) {
				sb.append(",");
			}
		}
		sb.append(" where ").append(idColumn).append("=").append(idValue);
		db.setData(sb.toString());
		db.close();
	}

	public void del(Object o) {
		// delete from 表名 where 条件(主键=xxx)
		db = new DBControl();
		Class c = o.getClass();
		String classname = c.getName();
		TableInfo table = Constant.TABLEMAP.get(classname);
		List<OneToMany> oneList = table.getOneList();// oneList 代表级联关系,不可以删除
		if (oneList != null) {
			System.out.println("有级联关系,不可以删除");
			db.close();
			return;
		}
		Id id = table.getId();
		String idColumn = id.getColumn();
		String idName = id.getName();
		Object idValue = getValueByObject(idName, o);
		if (null == id) {
			System.out.println("没有设置主键");
		}
		if(idValue instanceof String){
			idValue="'"+idValue+"'";
		}
		String sqlString = "delete from " + table.getTableName() + " where "
				+ idColumn + "=" + idValue;
		db.setData(sqlString);
		db.close();
	}

	public List<Object> queryList(String lql) {
		db = new DBControl();
		SQLInfo info = SQLTools.getSQLInfo(lql);
		//[start]查询语句from区域的解析工作. 遍历Constant.TABLEMAP 获得相应的from区域的 实体的表信息
		String className = info.getTableName();
		Map<String,TableInfo> map = Constant.TABLEMAP;
		Set<String> set = map.keySet();
		Iterator<String> it = set.iterator();
		TableInfo table = null;
		while(it.hasNext()){
			String key= it.next();
			String[] ts = key.split("\\.");
			if(className.equals(ts[ts.length-1])){
				table=map.get(key);
			}
		}
		//[end]
		String sql = "select * from "+table.getTableName();
		//[start]拼接sql中,条件以及父表(manyToOne)映射工作
		List<ManyToOne> manyList = table.getManyList();
		List<String> manyCondition = new ArrayList<String>();
		if(manyList!=null){
			for(ManyToOne many:manyList){
				String manyClassName =many.getManyClass();
				TableInfo manyTable = map.get(manyClassName);
				String manyTableName = manyTable.getTableName();
				sql+=","+manyTableName+" ";
				String manyc = table.getTableName()+"."+many.getManyColumn()+"="+manyTableName+'.'+manyTable.getId().getColumn();
				manyCondition.add(manyc);
			} 
			sql+="where ";
			for(String cs :manyCondition){
				sql+=cs;
			}
		}
		List<String> condition = info.getCondition();
		List<String> operation = info.getOperation();
		StringBuffer whereStr = new StringBuffer();
		if(condition!=null&&condition.size()>0){
			sql+=" and ";
			for(int i = 0 ;i<condition.size();i++){
				whereStr.append(table.getTableName()+"."+condition.get(i)).append(" ");
				if(i!=condition.size()-1){
					whereStr.append(operation.get(i)).append(" ");
				}
			}
		} 
		 sql+=whereStr;
		//[end]
		System.out.println(sql);
		ResultSet rs = db.getData(sql); //执行并获得数据
		//[start]  数据库获得数据后 进行实体映射
		List<Object> list = new ArrayList<Object>();
	 
		Id id = table.getId();
		List<Property> pList = table.getPropertys();
		try {
			while(rs.next()){
				Class mainClazz = Class.forName(table.getClassName());
				Object mainObject = mainClazz.newInstance(); 
			//[start]step1:mainObject中的id 与 很多property的赋值阶段
				Field mainObject_Id_field = mainClazz.getDeclaredField(id.getName());//拿到参数的资料.//private int com.lowkey.bean.Style.styleId
				Class mainObject_Id_Type = mainObject_Id_field.getType();//拿到参数的类型.int类型
				// mainClazz.getDeclaredMethod（方法名字,"返回类型"） .然后 找到 这个方法.!
				Method mainObject_Id_Method = mainClazz.getDeclaredMethod("set"+id.getName().substring(0,1).toUpperCase()+id.getName().substring(1),mainObject_Id_Type);
				mainObject_Id_Method.invoke(mainObject, rs.getObject(table.getTableName()+"."+id.getColumn()));//调用这个我们方法
				if(pList!=null){
					for(Property p:pList){
						Field pf  = mainClazz.getDeclaredField(p.getName());
						Class pc = pf.getType();
						Method pMethod = mainClazz.getDeclaredMethod("set"+p.getName().substring(0,1).toUpperCase()+p.getName().substring(1),pc);
						pMethod.invoke(mainObject,rs.getObject(table.getTableName()+"."+p.getColumn()));
					}
				}
			//[end]
			//[start]step2:mainObject中的很多manyToOne的赋值阶段.  (就是对manyToOne中定义的父表的那些类,进行赋值)
				if(manyList != null){
					for(ManyToOne m : manyList){
						String manyClass  = m.getManyClass();
						TableInfo manyTable = map.get(manyClass);
						Class manyc = Class.forName(manyClass);
						Object manyo = manyc.newInstance();//这里就拿到了manytoone 中的类的实例了！
						//设置上每个manytoone 的id域和property域
						Id manyId = manyTable.getId();
						Field midf= manyc.getDeclaredField(manyId.getName());
						Class midtype = midf.getType();
						Method midMethod = manyc.getDeclaredMethod("set"+manyId.getName().substring(0,1).toUpperCase()+manyId.getName().substring(1), midtype);
						midMethod.invoke(manyo, rs.getObject(manyTable.getTableName()+"."+ manyId.getColumn()));
						List<Property> manyPropertyList = manyTable.getPropertys();
						if(manyPropertyList!=null){
							for(Property p:manyPropertyList){
								Field pf  = manyc.getDeclaredField(p.getName());
								Class pc = pf.getType();
								Method pMethod = manyc.getDeclaredMethod("set"+p.getName().substring(0,1).toUpperCase()+p.getName().substring(1),pc);
								pMethod.invoke(manyo,rs.getObject(manyTable.getTableName()+"."+p.getColumn()));
							}
						}
						//然后把这个父级(manyToOne)对象注入到子对象中.
						Method mChildSetParent = mainClazz.getDeclaredMethod("set"+m.getManyName().substring(0,1).toUpperCase()+m.getManyName().substring(1), manyc);
						mChildSetParent.invoke(mainObject,manyo);
					}
				}
			//[end]
			 
			list.add(mainObject);
			}
		} 
		//[start] 异常区域
		catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} finally {
			db.close();
		}
		//[end]
		//[end]
		return list;
	}

	public List query(String lql) {

		return null;
	} 

	 

	public List queryList(LowkeyDetachedCriteria deta)  {
		db = new DBControl();
		String sql= deta.getSql();
		List resultList = new ArrayList();
		System.out.println(sql);
		ResultSet  rs = db.getData(sql);
		TableInfo table = deta.getTable();
		
		List<Property> pList = table.getPropertys();
		Id id = table.getId();
		
		try {
			while(rs.next()){
				Class mainClazz = Class.forName(table.getClassName());
				Object mainObejct = mainClazz.newInstance(); 
			// mainObject中的id 与 很多property的赋值阶段
				Field mainObject_Id_field = mainClazz.getDeclaredField(id.getName());//拿到参数的资料.//private int com.lowkey.bean.Style.styleId
				Class mainObject_Id_Type = mainObject_Id_field.getType();//拿到参数的类型.int类型
				// mainClazz.getDeclaredMethod（方法名字,"返回类型"） .然后 找到 这个方法.!
				Method mainObject_Id_Method = mainClazz.getDeclaredMethod("set"+id.getName().substring(0,1).toUpperCase()+id.getName().substring(1),mainObject_Id_Type);
				mainObject_Id_Method.invoke(mainObejct, rs.getObject(table.getTableName()+"."+id.getColumn()));//调用这个我们方法
				if(pList!=null){
					for(Property p:pList){
						Field pf  = mainClazz.getDeclaredField(p.getName());
						Class pc = pf.getType();
						Method pMethod = mainClazz.getDeclaredMethod("set"+p.getName().substring(0,1).toUpperCase()+p.getName().substring(1),pc);
						pMethod.invoke(mainObejct,rs.getObject(table.getTableName()+"."+p.getColumn()));
					}
				}
			resultList.add(mainObejct);	
			}
		}catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} finally {
			db.close();
		}
		return resultList;
	}
	
	@Override
	public Object queryFromCache(String name, String lql, long time) {
		Object o = null;
		CacheFactory cf = new CacheFactory();
		o= cf.getFromCache(name);
		if(o!=null){
			System.out.println("from Cache");
		}else{
			//如果缓存中,没有我们要的结果,就查询数据库
			List list  = queryList(lql);
			System.out.println("from DB");
			//然后把查询得到的结果放入缓存中.
			cf.addCache(name, list, time);
			o = cf.getFromCache(name);//然后再次从缓存中获得.
		}
		return o;
	}
	
	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
 		lowkeyDao dao  =new lowkeyDaoImpl(); 
 		List<Book> list = (List<Book>) dao.queryFromCache("Book","from Book",5000);
 		System.out.println(list.size());
 		List<Book> blist = (List<Book>) dao.queryFromCache("Book","from Book",5000);
 		System.out.println(CacheMap.CACHEMAP.get("Book"));
 		try {
			Thread.sleep(8000);
			System.out.println(CacheMap.CACHEMAP.get("Book"));
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
 		
 		
//// 		Style s = new Style();
//// 		s.setStyleId(3);
//// 		s.setStyle("aaaaaaaaaa");
//// 		dao.save(s);
// 		
// 	//	List<Style>  sList =  dao.queryList("from  Book where Book.styleId=style.styleId and bookId =1");
////		for(Style s : sList){
////		System.out.println(s.getStyleId()+"		"+s.getStyle());
////	}
// 		
////		LowkeyDetachedCriteria deta = new LowkeyDetachedCriteria();
////		deta.setEntity(Book.class);
////		deta.addRestrictions(new Restrictions().in("BookId", new Integer[]{1,2,3,4}));
//// 		List<Book>  bList = dao.queryList(deta);
// 		List<Book>  bList =  dao.queryList("from  Book where styleId=3 or styleId =1 ");
// 		for(Book b : bList){
// 			System.out.println(b.getBookId()+"		"+b.getAuthor()+"  "+b.getStyle().getStyle()+" " +b.getStyle().getStyleId());
// 			System.out.println(b.getBookId()+"		"+b.getAuthor());
// 		}
 		
	}

 
}







